#include "incs.h"

#include "InGameState.h"
#include "OgreApplication.h"
#include "GameManager.h"
#include "MiscOgre.h"

#include <Caelum.h>


void InGameState::createScene()
{
	using namespace Ogre;
	using namespace caelum;

	Ogre::Root * root = Ogre::Root::getSingletonPtr();
	mSceneMgr = root->createSceneManager(Ogre::ST_EXTERIOR_REAL_FAR, "InGameStateSceneManager");

	mCamera = mSceneMgr->createCamera("LoginScreen Camera");
	mViewport = root->getAutoCreatedWindow()->addViewport(mCamera);
	mCamera->setFarClipDistance(100000000);
	mCamera->setNearClipDistance(0.01);
	mSceneMgr->setAmbientLight( Ogre::ColourValue( 0.1, 0.1, 0.1 ) );
	//	mViewport->setBackgroundColour( Ogre::ColourValue(0, 0.1, 0.1));

	/* FIRST, CREATE STATIC GEOMETRY */

	Entity * terrainEnt = mSceneMgr->createEntity("TerrainEnt", "Terrain4.mesh");
	SceneNode * terrainNode = mSceneMgr->getRootSceneNode()->
		createChildSceneNode("TerrainNode");
	//terrainNode->attachObject(terrainEnt);
	////terrainNode->setScale(49, 49, 49);
	//terrainNode->setScale(1000, 1000, 1000);
	//terrainNode->setPosition(0, 0, 1200);
	terrainEnt->setMaterialName("Wikisample/alphaterrain");
	Ogre::StaticGeometry * staticGeom = mSceneMgr->createStaticGeometry("TerrainGeom");
	staticGeom->addEntity(terrainEnt, Ogre::Vector3(0, 0, 1200),
		Ogre::Quaternion::IDENTITY, Ogre::Vector3(400, 400, 400));

	Entity * towerEnt = mSceneMgr->createEntity("Tower", "Tower.mesh");
	mTowerNode = mSceneMgr->getRootSceneNode()->
		createChildSceneNode("TowerNode");
	mTowerNode->attachObject(towerEnt);
	mTowerNode->setPosition(Vector3(0, -912, 1200));
	mTowerNode->setScale(.3, .3, .3);
	mTowerNode->setPosition(0, -0, 1200);

	OgreNewt::CollisionPrimitives::TreeCollisionSceneParser * tcsp = new
		OgreNewt::CollisionPrimitives::TreeCollisionSceneParser(GetPhysWorld());
	tcsp->parseScene(mSceneMgr->getRootSceneNode(), true);
	OgreNewt::Body * worldGeom = new OgreNewt::Body(GetPhysWorld(), tcsp);


	/* NOW, CREATE THE SKY */

	//mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8, 5000);

	//mCaelumSystem = new caelum::CaelumSystem (root, mSceneMgr, 
	//	(CaelumSystem::CaelumComponent)
	//	(caelum::CaelumSystem::CAELUM_COMPONENT_SUN | 
	//	caelum::CaelumSystem::CAELUM_COMPONENT_CLOUDS |
	//	caelum::CaelumSystem::CAELUM_COMPONENT_SKY_COLOUR_MODEL |
	//	caelum::CaelumSystem::CAELUM_COMPONENT_SKY_DOME |
	//	caelum::CaelumSystem::CAELUM_COMPONENT_SOLAR_SYSTEM_MODEL
	//	 
	//	) );

	mCaelumSystem = new caelum::CaelumSystem (root, mSceneMgr, 
		(CaelumSystem::CaelumComponent)
		(caelum::CaelumSystem::CAELUM_COMPONENTS_DEFAULT |
		caelum::CaelumSystem::CAELUM_COMPONENT_CLOUDS

		) );

	mCaelumSystem->setManageSceneFog(true);
	mCaelumSystem->setSceneFogDensityMultiplier(0.0005);
	//mCaelumSystem->getSun()->setAmbientMultiplier (Ogre::ColourValue(0.5, 0.5, 0.5));
	//mCaelumSystem->getSun()->setDiffuseMultiplier (Ogre::ColourValue(3, 3, 2.7));
	//mCaelumSystem->getSun()->setSpecularMultiplier (Ogre::ColourValue(2, 2, 2));
	mCaelumSystem->getClouds()->setCloudCover(0);
	mCaelumSystem->getClouds()->setCloudSpeed(Ogre::Vector2(0, 0.005));
	mCaelumSystem->getClouds()->setCloudBlendTime(2.0);
	mCaelumSystem->getClouds()->setCloudDetailOffset(Vector2(3, 4));
	//mCaelumSystem->getSun()->setManageAmbientLight (true);
	//mCaelumSystem->getStarfield ()->setInclination (Degree (13));

	// Winter dawn in the Sidney.
	mCaelumSystem->getUniversalClock ()->setGregorianDateTime (2008, 12, 4, 15, 33, 0);
	mCaelumSystem->getUniversalClock()->setTimeScale(1000);
	mCaelumSystem->getSolarSystemModel ()->setObserverLongitude (Ogre::Degree(151 + 12.0 / 60));
	mCaelumSystem->getSolarSystemModel ()->setObserverLatitude (Ogre::Degree(-33 + 52.0 / 60));


	OgreApp.getRenderWindow()->addListener (mCaelumSystem);
	root->addFrameListener (mCaelumSystem);


	/* NOW, CREATE OTHER ENTITIES */

	Ogre::Entity * robEnt  = mSceneMgr->createEntity("RobotL", "robot.mesh");
	Ogre::SceneNode * robNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(
		"RobotLNode", Ogre::Vector3(0, 0, -100) );
	robNode->setScale(.5, .5, .5);
	robNode->attachObject(robEnt);
	robNode->yaw(Ogre::Degree(40));
	robNode->translate(0, 0, -10, Ogre::Node::TS_LOCAL);


	robNode->translate(0, 1000, 0, Ogre::Node::TS_LOCAL);

	robNode->attachObject(mCamera);

	robEnt->setMaterialName("Wikisample/alphaterrain");
	
	


	mCamera->yaw(Ogre::Degree(180));
	mCamera->setPosition(Ogre::Vector3(0, -912, 1200));


	Entity * probEnt = mSceneMgr->createEntity("probot", "ninja.mesh");
	SceneNode * probNode = mSceneMgr->getRootSceneNode()->
		createChildSceneNode("probotNode");
	probNode->attachObject(probEnt);
	probNode->setPosition(Vector3(0, -912, 1200));
	probNode->setScale(1, 1, 1);
	probNode->setPosition(0, 50, 1300);
	probNode->yaw(Ogre::Degree(30));

	Ogre::AxisAlignedBox aabb = probEnt->getBoundingBox();
	//OgreNewt::CollisionPrimitives::Box * probCyl = 
	//	new OgreNewt::CollisionPrimitives::Box(GetPhysWorld(), 
	//	aabb.getSize());
	
	
	OgreNewt::CollisionPrimitives::ConvexHull * probCH = new
		OgreNewt::CollisionPrimitives::ConvexHull(GetPhysWorld(), 
		probNode );
		
	OgreNewt::Body * probBody = new OgreNewt::Body(GetPhysWorld(), probCH);
	probBody->attachToNode(probNode);
	
	probBody->setPositionOrientation(probNode->getPosition(), 
		probNode->getOrientation());

	probBody->setMassMatrix(500, Vector3(0, 0, 0));
	probBody->setVelocity(Ogre::Vector3(0, 10, +120));
	probBody->setStandardForceCallback();

	probBody->setContinuousCollisionMode(true);



	//probBody->setPositionOrientation(
	//	probNode->getPosition() + aabb.getSize(), probNode->getOrientation());

	//probNode->showBoundingBox(true);

	//probEnt->setMaterialName("Wikisample/alphaterrain");


	//towerEnt->setMaterialName("Wikisample/alphaterrain");




	// Create the SUN
	mSunLight = mSceneMgr->createLight("SunLight");
	mSunLight->setType(Ogre::Light::LightTypes::LT_DIRECTIONAL);
	mSunLight->setDirection(Vector3(1*500, -3*500, 1*500));
	mSunLight->setVisible(false);


	mCamera->lookAt(mTowerNode->getPosition());


	SetupCEGUI(root->getAutoCreatedWindow(), mSceneMgr);
}



bool InGameState::frameStarted( Ogre::FrameEvent const & evt )
{
	//OgreNewt::Debugger & physDebugger = OgreNewt::Debugger::getSingleton();
	//physDebugger.showLines( GetPhysWorld() );

	// Update camera control.
	GameManager & gm = getGameManager();
	OIS::MouseState const & ms = OgreApp.getMouse()->getMouseState();
	mCameraControl->Update(this, evt.timeSinceLastFrame, gm.getKeysState(), ms, 
		mSceneMgr); 

	// Update FPS stats
	Ogre::RenderWindow * renderWin = OgreApp.getRenderWindow();
	updateStats(renderWin);

	UpdatePhysicsWorld(evt.timeSinceLastFrame);

	return true;
}

void InGameState::keyPressed( OIS::KeyEvent const & e )
{
	CEGUI::System *sys = CEGUI::System::getSingletonPtr();
	sys->injectKeyDown(e.key);
	sys->injectChar(e.text);

	if(e.key == OIS::KC_ESCAPE)
		getGameManager().ShouldExit(true);
	
	if(e.key == OIS::KC_Z)
	{
		mTowerScale += 5.0;
		mTowerNode->setScale(mTowerScale, mTowerScale, mTowerScale);
		std::cout << "Scale: " << mTowerScale;
	}
	else if(e.key == OIS::KC_X)
	{
		mTowerScale -= 5.0;
		mTowerNode->setScale(mTowerScale, mTowerScale, mTowerScale);
		std::cout << "Scale: " << mTowerScale;
	}

	if(e.key == OIS::KC_N)
	{
		mSunLight->setDiffuseColour(Ogre::ColourValue(0.1, 0.1, 0.1));
		//mSunLight->setPowerScale(mSunLight->getPowerScale() + .5);
		//std::cout << "Scale: " << mSunLight->getPowerScale();
	}
	else if(e.key == OIS::KC_M)
	{
		mSunLight->setDiffuseColour(Ogre::ColourValue(0.5, 0.5, 0.5));
		//mSunLight->setPowerScale(mSunLight->getPowerScale() - .5);
		//std::cout << "Scale: " << mSunLight->getPowerScale();
	}

}

void InGameState::keyReleased( OIS::KeyEvent const & e )
{
	CEGUI::System::getSingleton().injectKeyUp(e.key);
}

bool InGameState::mousePressed( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
	CEGUI::System::getSingleton().injectMouseButtonDown(
		MiscOgre::OISButtonToCEGUI(id));
	return true;
}

bool InGameState::mouseReleased( const OIS::MouseEvent &e, OIS::MouseButtonID id )
{
	CEGUI::System::getSingleton().injectMouseButtonUp(
		MiscOgre::OISButtonToCEGUI(id));
	return true;
}

bool InGameState::mouseMoved( const OIS::MouseEvent &e )
{
	CEGUI::System::getSingleton().injectMouseMove(e.state.X.rel, e.state.Y.rel);
	return true;
}

void InGameState::createGUI()
{

	//// Load the layout.
	//CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton().
	//	loadWindowLayout((CEGUI::utf8*)"GameMenuTest.layout"); 
	//GetGUISystem()->setGUISheet(sheet);

	//long double p;

	//// Subscribe to Exit event.
	//CEGUI::WindowManager *wmgr = CEGUI::WindowManager::getSingletonPtr();
	//CEGUI::Window * exitButton = wmgr->getWindow((CEGUI::utf8*)"ExitButton");
	//exitButton->subscribeEvent(CEGUI::PushButton::EventClicked,
	//	CEGUI::Event::Subscriber(&LoginScreenState::OnGUIExit, this));


	//// Subscribe to Login event.
	//CEGUI::Window * loginButton= wmgr->getWindow((CEGUI::utf8*)"LoginButton");
	//exitButton->subscribeEvent(CEGUI::PushButton::EventClicked,
	//	CEGUI::Event::Subscriber(&LoginScreenState::OnGUILogin, this));

}

bool InGameState::OnGUIExit( const CEGUI::EventArgs & e )
{
	getGameManager().ShouldExit(true);
	return true;
}

bool InGameState::OnGUILogin( const CEGUI::EventArgs & e )
{
	return true;
}

void InGameState::enter()
{
	CreatePhysicsWorld();

	createScene();
	createGUI();
	EnableMouseCursor(false);
	
	enableDebugOverlay(true);

	mCameraControl.reset(new CameraControl(mCamera));

	InitializePhysicsDebugger(mSceneMgr);
}

void InGameState::exit()
{
	DestroyPhysicsWorld();

	Ogre::Root * root = Ogre::Root::getSingletonPtr();
	root->destroySceneManager(mSceneMgr);
}

InGameState::InGameState( GameManager & gameManager ) : 
	GameState(gameManager), CEGUIOwner(),
mCamera(0), mSceneMgr(0), mViewport(0), mTowerScale(500), mCaelumSystem(0)
{

}

const char * InGameState::getStateName()
{
	return "InGameState";
}
